package com.itheima.stock.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.stock.constant.StockConstant;
import com.itheima.stock.security.utils.JwtTokenUtil;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.R;
import com.itheima.stock.vo.resp.ResponseCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 认证过滤器
 * 登录认证信息并办法jwt票据
 */
public class JwtLoginAuuthenticationFilter extends AbstractAuthenticationProcessingFilter {


    private RedisTemplate redisTemplate;

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 自定义过滤器，传入的登录认证的url地址
     *
     * @param defaultFilterProcessesUrl
     */
    public JwtLoginAuuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }

    /**
     * post /mylog
     * data: {“username","itheima","password","123456"}
     * 尝试如认证的核心方法
     *
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     * @throws IOException
     * @throws ServletException
     */
    @Override

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        //登录请求必须为post 并且需要为json格式
        if (!request.getMethod().equalsIgnoreCase("POST") || !MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(request.getContentType())) {
            throw new AuthenticationServiceException("请求方式：" + request.getMethod() + "请求格式：" + request.getContentType());
        }
        //获取pst请求ajsx请求传入的数据流
        //request.getInputStream() ajax提交的输入流对象（ajsx提交是json格式）
        //HashMap.class 封装成LoginReqVo 用户对象
        LoginReqVo reqVo = new ObjectMapper().readValue(request.getInputStream(), LoginReqVo.class);
        //校验输入的验证码是否正确
        //判断redis中保存的验证码与输入的验证码是否相同（比较时忽略大小写校验验证码
        String redisCode = (String) redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + reqVo.getSessionId());
        //告诉前端返回的数据格式为json格式
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        //响应的编码格式
        response.setCharacterEncoding("UTF-8");
        if (StringUtils.isBlank(redisCode)) {
            R<Object> error = R.error(ResponseCode.CHECK_CODE_TIMEOUT);
            String jsonData = new ObjectMapper().writeValueAsString(error);//构建流返回
            response.getWriter().write(jsonData);
            return null;
        }

        String username = reqVo.getUsername();
        username = (username != null) ? username : "";
        username = username.trim();//去掉前后空格
        String password = reqVo.getPassword();
        password = (password != null) ? password : "";
        password = password.trim();//去掉前后空格

        //组装认证的票据对象
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        //交给认证管理器 认证密码
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    /**
     * 认证成功后执行的方法
     *
     * @param request
     * @param response
     * @param chain      过滤器链
     * @param authResult 认证对象信息，用户名密码
     *                   method.
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//        User principal = ((User) authResult.getPrincipal());
//        String username = principal.getUsername();
//        Collection<GrantedAuthority> authorities = principal.getAuthorities();//权限
//        //生成票据 "[P5,ROLE_ADMIN]" --权限
//        String tokenStr = JwtTokenUtil.createToken(username, authorities.toString());
//
//        //返回数据给前端
//        //告诉前端返回的数据格式为json格式
//        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
//        //响应的编码格式
//        response.setCharacterEncoding("UTF-8");
//        //构建响应对象
//        //响应  .writeValueAsString(info) 把数据转为json响应
//        response.getWriter().write(new ObjectMapper().writeValueAsString(info));
    }


    /**
     * 认证失败
     *
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
//        //返回数据给前端
//        //告诉前端返回的数据格式为json格式
//        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
//        //响应的编码格式
//        response.setCharacterEncoding("UTF-8");
//        Map<String, String> info = new HashMap<>();
//        info.put("msg", "登录失败");
//        info.put("data", "");
//        info.put("code", "0");
//        //响应  .writeValueAsString(info) 把数据转为json响应
//        response.getWriter().write(new ObjectMapper().writeValueAsString(info));
    }
}






































